package com.baizhi.componet;

import com.alibaba.fastjson.JSON;
import com.baizhi.vo.LogBean;
import com.google.common.collect.Maps;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.joda.time.LocalDateTime;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * aop 切面 结合mongodb 实现保存操作日志
 *
 * @author Administrator
 */
@Aspect
@Component
@Slf4j
public class LogAspect {
    @Resource
    private MongoTemplate mongoTemplate;

    /**
     * 权限修饰符 包.类.方法(任意参数)
     */
    @Pointcut("execution(* com.baizhi.controller.*.*(..))")
    public void logCut() {

    }

    @SneakyThrows
    @Around("logCut()")
    public Object around(ProceedingJoinPoint joinPoint) {
        Object proceed = joinPoint.proceed();
        // 当前控制器反射对象
        Signature signature = joinPoint.getSignature();
        MethodSignature ms = (MethodSignature) signature;
        //方法反射对象
        //方法名称 类名称
        Method method = ms.getMethod();
        //存放map集合统一管理
        HashMap<String, String> map = Maps.newHashMap();

        String typeName = method.getDeclaringClass().getSimpleName();
        String typeSwaggerDescription = "";
        String methodName = method.getName();
        String methodSwaggerValue = "";
        map.put("typeName", typeName);
        map.put("methodName", methodName);

        //获取方法注解
        Annotation[] methodAnnotations = method.getDeclaredAnnotations();
        for (Annotation annotation : methodAnnotations) {
            if (annotation instanceof ApiOperation) {
                //swagger方法注解对象
                ApiOperation api = ((ApiOperation) annotation);
                methodSwaggerValue = api.value();
                //方法描述
                map.put("methodSwaggerV", methodSwaggerValue);
                log.info("MethodV:{}", methodSwaggerValue);

            }
        }
        //获取类上的注解
        Annotation[] typeAnnotations = method.getDeclaringClass().getDeclaredAnnotations();
        for (Annotation annotation : typeAnnotations) {
            if (annotation instanceof Api) {
                Api api = ((Api) annotation);
                typeSwaggerDescription = api.description();
                //类描述
                map.put("typeSwaggerDesc", typeSwaggerDescription);
                log.info("description:{}", typeSwaggerDescription);
            }
        }
        Object[] args = joinPoint.getArgs();
        saveLog(map, args);
        return proceed;
    }

    /**
     * @param paramMap
     */
    public void saveLog(Map<String, String> paramMap, Object[] args) {
        //获取请求参数 获取请求路径 获取方法名称 获取方法描述 获取控制器类名称 获取控制器类描述
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest req = requestAttributes.getRequest();
        Map<String, String[]> map = req.getParameterMap();
        String requestUrl = req.getRequestURL().toString();
        LogBean bean = new LogBean();
        bean.setTypeName(paramMap.get("typeName"));
        bean.setTypeNameSwaggerDesc(paramMap.get("typeSwaggerDesc"));
        bean.setMethodName(paramMap.get("methodName"));
        bean.setMethodSwaggerV(paramMap.get("methodSwaggerV"));
        //请求参数 params
        bean.setParams(JSON.toJSONString(map));
        //切点参数 args
        bean.setArgs(JSON.toJSONString(args));
        bean.setRequestUrl(requestUrl);
        //createTime
        bean.setCreateTime(new Date());
        //存储到mongodb
        mongoTemplate.insert(bean);
        bean = null;
        System.gc();
    }
}
